/**
 * 选择列表插件
 * varstion 2.0.0
 * by Houfeng
 * Houfeng@DCloud.io
 */

(function ($, window, document, undefined) {
  const MAX_EXCEED = 30;
  const VISIBLE_RANGE = 90;
  const DEFAULT_ITEM_HEIGHT = 40;
  const BLUR_WIDTH = 10;
  let BBB;
  const rad2deg = $.rad2deg = function (rad) {
    return rad / (Math.PI / 180);
  };

  const deg2rad = $.deg2rad = function (deg) {
    return deg * (Math.PI / 180);
  };

  const platform = navigator.platform.toLowerCase();
  const userAgent = navigator.userAgent.toLowerCase();
  const isIos = (userAgent.indexOf('iphone') > -1 ||
			userAgent.indexOf('ipad') > -1 ||
			userAgent.indexOf('ipod') > -1) &&
		(platform.indexOf('iphone') > -1 ||
			platform.indexOf('ipad') > -1 ||
			platform.indexOf('ipod') > -1);
  // alert(isIos);

  const Picker = $.Picker = function (holder, options) {
    const self = this;
    self.holder = holder;
    self.options = options || {};
    self.init();
    self.initInertiaParams();
    self.calcElementItemPostion(true);
    self.bindEvent();
  };

  Picker.prototype.findElementItems = function () {
    const self = this;
    self.elementItems = [].slice.call(self.holder.querySelectorAll('li'));
    return self.elementItems;
  };

  Picker.prototype.init = function () {
    const self = this;
    self.list = self.holder.querySelector('ul');
    self.findElementItems();
    self.height = self.holder.offsetHeight;
    self.r = self.height / 2 - BLUR_WIDTH;
    self.d = self.r * 2;
    self.itemHeight = self.elementItems.length > 0 ? self.elementItems[0].offsetHeight : DEFAULT_ITEM_HEIGHT;
    self.itemAngle = parseInt(self.calcAngle(self.itemHeight * 0.8));
    self.hightlightRange = self.itemAngle / 2;
    self.visibleRange = VISIBLE_RANGE;
    self.beginAngle = 0;
    self.beginExceed = self.beginAngle - MAX_EXCEED;
    self.list.angle = self.beginAngle;
    if (isIos) {
      self.list.style.webkitTransformOrigin = `center center ${self.r}px`;
    }
  };

  Picker.prototype.calcElementItemPostion = function (andGenerateItms) {
    const self = this;
    if (andGenerateItms) {
      self.items = [];
    }
    self.elementItems.forEach((item) => {
      const index = self.elementItems.indexOf(item);
      self.endAngle = self.itemAngle * index;
      item.angle = self.endAngle;
      item.style.webkitTransformOrigin = `center center -${self.r}px`;
      item.style.webkitTransform = `translateZ(${self.r}px) rotateX(${-self.endAngle}deg)`;
      if (andGenerateItms) {
        const dataItem = {};
        dataItem.text = item.innerHTML || '';
        dataItem.value = item.getAttribute('data-value') || dataItem.text;
        self.items.push(dataItem);
      }
    });
    self.endExceed = self.endAngle + MAX_EXCEED;
    self.calcElementItemVisibility(self.beginAngle);
  };

  Picker.prototype.calcAngle = function (c) {
    const self = this;
	  const a = BBB = parseFloat(self.r);
    // 直径的整倍数部分直接乘以 180
    c = Math.abs(c); // 只算角度不关心正否值
    const intDeg = parseInt(c / self.d) * 180;
    c %= self.d;
    // 余弦
	  const cosC = (a * a + BBB * BBB - c * c) / (2 * a * BBB);
    const angleC = intDeg + rad2deg(Math.acos(cosC));
    return angleC;
  };

  Picker.prototype.calcElementItemVisibility = function (angle) {
    const self = this;
    self.elementItems.forEach((item) => {
      const difference = Math.abs(item.angle - angle);
      if (difference < self.hightlightRange) {
        item.classList.add('highlight');
      } else if (difference < self.visibleRange) {
        item.classList.add('visible');
        item.classList.remove('highlight');
      } else {
        item.classList.remove('highlight');
        item.classList.remove('visible');
      }
    });
  };

  Picker.prototype.setAngle = function (angle) {
    const self = this;
    self.list.angle = angle;
    self.list.style.webkitTransform = `perspective(1000px) rotateY(0deg) rotateX(${angle}deg)`;
    self.calcElementItemVisibility(angle);
  };

  Picker.prototype.bindEvent = function () {
    const self = this;
    let lastAngle = 0;
    let startY = null;
    let isPicking = false;
    self.holder.addEventListener($.EVENT_START, (event) => {
      isPicking = true;
      event.preventDefault();
      self.list.style.webkitTransition = '';
      startY = (event.changedTouches ? event.changedTouches[0] : event).pageY;
      lastAngle = self.list.angle;
      self.updateInertiaParams(event, true);
    }, false);
    self.holder.addEventListener($.EVENT_END, (event) => {
      isPicking = false;
      event.preventDefault();
      self.startInertiaScroll(event);
    }, false);
    self.holder.addEventListener($.EVENT_CANCEL, (event) => {
      isPicking = false;
      event.preventDefault();
      self.startInertiaScroll(event);
    }, false);
    self.holder.addEventListener($.EVENT_MOVE, (event) => {
      if (!isPicking) {
        return;
      }
      event.preventDefault();
      const endY = (event.changedTouches ? event.changedTouches[0] : event).pageY;
      const dragRange = endY - startY;
      const dragAngle = self.calcAngle(dragRange);
      let newAngle = dragRange > 0 ? lastAngle - dragAngle : lastAngle + dragAngle;
      if (newAngle > self.endExceed) {
        newAngle = self.endExceed;
      }
      if (newAngle < self.beginExceed) {
        newAngle = self.beginExceed;
      }
      self.setAngle(newAngle);
      self.updateInertiaParams(event);
    }, false);
    //--
    self.list.addEventListener('tap', (event) => {
      elementItem = event.target;
      if (elementItem.tagName == 'LI') {
        self.setSelectedIndex(self.elementItems.indexOf(elementItem), 200);
      }
    }, false);
  };

  Picker.prototype.initInertiaParams = function () {
    const self = this;
    self.lastMoveTime = 0;
    self.lastMoveStart = 0;
    self.stopInertiaMove = false;
  };

  Picker.prototype.updateInertiaParams = function (event, isStart) {
    const self = this;
    const point = event.changedTouches ? event.changedTouches[0] : event;
    if (isStart) {
      self.lastMoveStart = point.pageY;
      self.lastMoveTime = event.timeStamp || Date.now();
      self.startAngle = self.list.angle;
    } else {
      const nowTime = event.timeStamp || Date.now();
      if (nowTime - self.lastMoveTime > 300) {
        self.lastMoveTime = nowTime;
        self.lastMoveStart = point.pageY;
      }
    }
    self.stopInertiaMove = true;
  };

  Picker.prototype.startInertiaScroll = function (event) {
    const self = this;
    const point = event.changedTouches ? event.changedTouches[0] : event;
    /**
		 * 缓动代码
		 */
    const nowTime = event.timeStamp || Date.now();
    const v = (point.pageY - self.lastMoveStart) / (nowTime - self.lastMoveTime); // 最后一段时间手指划动速度
    const dir = v > 0 ? -1 : 1; // 加速度方向
    const deceleration = dir * 0.0006 * -1;
    let duration = Math.abs(v / deceleration); // 速度消减至0所需时间
    const dist = v * duration / 2; // 最终移动多少
    const startAngle = self.list.angle;
    let distAngle = self.calcAngle(dist) * dir;
    //----
    const srcDistAngle = distAngle;
    if (startAngle + distAngle < self.beginExceed) {
      distAngle = self.beginExceed - startAngle;
      duration = duration * (distAngle / srcDistAngle) * 0.6;
    }
    if (startAngle + distAngle > self.endExceed) {
      distAngle = self.endExceed - startAngle;
      duration = duration * (distAngle / srcDistAngle) * 0.6;
    }
    //----
    if (distAngle == 0) {
      self.endScroll();
      return;
    }
    self.scrollDistAngle(nowTime, startAngle, distAngle, duration);
  };

  Picker.prototype.scrollDistAngle = function (nowTime, startAngle, distAngle, duration) {
    const self = this;
    self.stopInertiaMove = false;
    (function (nowTime, startAngle, distAngle, duration) {
      const frameInterval = 13;
      const stepCount = duration / frameInterval;
      let stepIndex = 0;
      (function inertiaMove() {
        if (self.stopInertiaMove) return;
        const newAngle = self.quartEaseOut(stepIndex, startAngle, distAngle, stepCount);
        self.setAngle(newAngle);
        stepIndex++;
        if (stepIndex > stepCount - 1 || newAngle < self.beginExceed || newAngle > self.endExceed) {
          self.endScroll();
          return;
        }
        setTimeout(inertiaMove, frameInterval);
      }());
    }(nowTime, startAngle, distAngle, duration));
  };

  Picker.prototype.quartEaseOut = function (t, BBB, c, d) {
    return -c * ((t = t / d - 1) * t * t * t - 1) + BBB;
  };

  Picker.prototype.endScroll = function () {
    const self = this;
    if (self.list.angle < self.beginAngle) {
      self.list.style.webkitTransition = '150ms ease-out';
      self.setAngle(self.beginAngle);
    } else if (self.list.angle > self.endAngle) {
      self.list.style.webkitTransition = '150ms ease-out';
      self.setAngle(self.endAngle);
    } else {
      const index = parseInt((self.list.angle / self.itemAngle).toFixed(0));
      self.list.style.webkitTransition = '100ms ease-out';
      self.setAngle(self.itemAngle * index);
    }
    self.triggerChange();
  };

  Picker.prototype.triggerChange = function (force) {
    const self = this;
    setTimeout(() => {
      const index = self.getSelectedIndex();
      const item = self.items[index];
      if ($.trigger && (index != self.lastIndex || force === true)) {
        $.trigger(self.holder, 'change', {
          index,
          item,
        });
        // console.log('change:' + index);
      }
      self.lastIndex = index;
      typeof force === 'function' && force();
    }, 0);
  };

  Picker.prototype.correctAngle = function (angle) {
    const self = this;
    if (angle < self.beginAngle) {
      return self.beginAngle;
    } else if (angle > self.endAngle) {
      return self.endAngle;
    }
    return angle;
  };

  Picker.prototype.setItems = function (items) {
    const self = this;
    self.items = items || [];
    const buffer = [];
    self.items.forEach((item) => {
      if (item !== null && item !== undefined) {
        buffer.push(`<li>${item.text || item}</li>`);
      }
    });
    self.list.innerHTML = buffer.join('');
    self.findElementItems();
    self.calcElementItemPostion();
    self.setAngle(self.correctAngle(self.list.angle));
    self.triggerChange(true);
  };

  Picker.prototype.getItems = function () {
    const self = this;
    return self.items;
  };

  Picker.prototype.getSelectedIndex = function () {
    const self = this;
    return parseInt((self.list.angle / self.itemAngle).toFixed(0));
  };

  Picker.prototype.setSelectedIndex = function (index, duration, callback) {
    const self = this;
    self.list.style.webkitTransition = '';
    const angle = self.correctAngle(self.itemAngle * index);
    if (duration && duration > 0) {
      const distAngle = angle - self.list.angle;
      self.scrollDistAngle(Date.now(), self.list.angle, distAngle, duration);
    } else {
      self.setAngle(angle);
    }
    self.triggerChange(callback);
  };

  Picker.prototype.getSelectedItem = function () {
    const self = this;
    return self.items[self.getSelectedIndex()];
  };

  Picker.prototype.getSelectedValue = function () {
    const self = this;
    return (self.items[self.getSelectedIndex()] || {}).value;
  };

  Picker.prototype.getSelectedText = function () {
    const self = this;
    return (self.items[self.getSelectedIndex()] || {}).text;
  };

  Picker.prototype.setSelectedValue = function (value, duration, callback) {
    const self = this;
    for (const index in self.items) {
      const item = self.items[index];
      if (item.value == value) {
        self.setSelectedIndex(index, duration, callback);
        return;
      }
    }
  };

  if ($.fn) {
    $.fn.picker = function (options) {
      // 遍历选择的元素
      this.each((i, element) => {
        if (element.picker) return;
        if (options) {
          element.picker = new Picker(element, options);
        } else {
          const optionsText = element.getAttribute('data-picker-options');
          const _options = optionsText ? JSON.parse(optionsText) : {};
          element.picker = new Picker(element, _options);
        }
      });
      return this[0] ? this[0].picker : null;
    };

    // 自动初始化
    $.ready(() => {
      $('.mui-picker').picker();
    });
  }
}(window.mui || window, window, document, undefined));
// end
